package util

import (
	"strings"

	"crypto/md5"
	"crypto/rand"

	"encoding/hex"
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"

	"sync"
)

const (
	success = iota
	warning
	fail
)

type ApiResult struct {
	Msg  string      `json:"msg"`
	Code int         `json:"code"`
	Data interface{} `json:"data"`
}

func ApiFail(msg string) ApiResult {
	return ApiResult{
		Code: fail,
		Msg:  msg,
	}
}

func ApiSuccess(msg string) ApiResult {
	return ApiResult{
		Code: success,
		Msg:  msg,
	}
}

func IfBlank(str, defaultStr string) string {
	if strings.TrimSpace(str) == "" {
		return defaultStr
	}
	return str
}

// Create Version 4 UUIDs as specified in RFC 4122
func uuidRFC() ([]byte, error) {
	b := make([]byte, 16)

	_, err := rand.Read(b[:])
	if err != nil {
		return nil, err
	}
	// Set the two most significant bits (bits 6 and 7) of the
	// clock_seq_hi_and_reserved to zero and one, respectively.
	b[8] = (b[8] | 0x40) & 0x7F

	// Set the four most significant bits (bits 12 through 15) of the
	// time_hi_and_version field to the 4-bit version number.
	b[6] = (b[6] & 0xF) | (4 << 4)
	return b, nil
}

// 36
// Create Version 4 UUIDs as specified in RFC 4122
func Uuid() (string, error) {
	b, err := uuidRFC()
	// Return unparsed version of the generated UUID sequence.
	return fmt.Sprintf("%x-%x-%x-%x-%x",
		b[0:4], b[4:6], b[6:8], b[8:10], b[10:]), err

}

//uuid 32
func SimpleUuid() (string, error) {
	b, err := uuidRFC()
	return fmt.Sprintf("%x", b), err
}

func resetIds(size int) {
	for idx := 0; idx < size; idx++ {
		uid, _ := SimpleUuid()
		id, _ := ShortIt(uid)
		ids = append(ids, id)
	}
}

var ids = []string{}

func NewShort() (short string) {
	mutex := new(sync.Mutex)
	mutex.Lock()
	defer mutex.Unlock()
	if len(ids) == 0 {
		resetIds(10) //初始化10个
	}
	short = ids[0] //取一个
	ids = ids[1:]
	return
}

// md5 加密字符串
func Md5(s string) string {
	h := md5.New()
	h.Write([]byte(s))
	return hex.EncodeToString(h.Sum(nil))
}

//转化为map
func ToMap(v interface{}) (map[string]interface{}, error) {
	j, err := json.Marshal(v)
	if err != nil {
		return nil, err
	}
	m := make(map[string]interface{})
	err = json.Unmarshal(j, &m)
	if err != nil {
		return nil, err
	}
	return m, nil
}

//转化为对象
func ToCombin(v interface{}, data map[string]interface{}) error {
	j, err := json.Marshal(data)
	if err != nil {
		return err
	}
	return json.Unmarshal(j, v)
}

//缩短为唯一串
func ShortIt(str string) (string, error) {
	dwz, err := dwz("dwz.cn/" + str)
	if err != nil {
		return "", nil
	}
	return ParseUrlPath(dwz)
}

//实现方式有点邪恶
//利用dwz.cn 缩短字符串
func dwz(u string) (string, error) {
	v := url.Values{}
	v.Set("url", u)
	resp, err := http.PostForm("http://dwz.cn/create.php", v)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	m := map[string]interface{}{}
	body, e := ioutil.ReadAll(resp.Body)
	if e != nil {
		return "", nil
	}
	err = json.Unmarshal(body, &m)
	if err != nil {
		return "", err
	}
	if m["status"].(float64) != 0 {
		return "", errors.New("状态值不为0,请求返回异常")
	}
	return m["tinyurl"].(string), nil
}

//解析url path
//url.cn/fjjd2J == >fjjd2J
func ParseUrlPath(rawurl string) (string, error) {
	u, e := url.Parse(rawurl)
	if e != nil {
		return "", e
	}
	if strings.HasPrefix(u.Path, "/") {
		return string(u.Path[1:]), nil
	}
	return u.Path, nil

}

//
func Substr(s string, start, length int) string {
	bt := []rune(s)
	if start < 0 {
		start = 0
	}
	var end int
	if (start + length) > (len(bt) - 1) {
		end = len(bt)
	} else {
		end = start + length
	}
	return string(bt[start:end])
}
